#pragma once

#include <QString>
#include <QList>
#include <math.h>
#include "variable.h"
#include "expresiones_global.h"

/*!
 * Contrato que deben cumplir las funciones que se usan en el compilador de expresiones.
 */
class EXPRESIONES_EXPORT Funcion
{
public:
    Funcion() {};
    virtual ~Funcion() {};
    virtual TIPO_VALOR evaluar(QList<TIPO_VALOR>& listaParametros) = 0;
    virtual int getNumeroParametros() = 0;
};

class EXPRESIONES_EXPORT FuncionBasica : public Funcion
{
public:
    FuncionBasica() {};
    virtual ~FuncionBasica() {};
    virtual TIPO_VALOR evaluar(QList<TIPO_VALOR>& listaParametros) { return 0; }
    int getNumeroParametros() { return numeroParametros; }
protected:
    int numeroParametros;
};

#define DECLARACION_FUNCION(CLASE, RESULTADO, NUMERO_PARAMETROS) \
    class CLASE : public FuncionBasica { \
    public: \
        CLASE() { numeroParametros = NUMERO_PARAMETROS; } \
        TIPO_VALOR evaluar(QList<TIPO_VALOR>& listaOperandos) { \
            return RESULTADO; \
        } \
    }; 

#define OPERANDO(i) (listaOperandos.size() > i ? listaOperandos[i] : VALOR_NULO)

DECLARACION_FUNCION(OperadorSuma, OPERANDO(0) + OPERANDO(1), 0)
DECLARACION_FUNCION(OperadorResta, OPERANDO(0) - OPERANDO(1), 0)
DECLARACION_FUNCION(OperadorMultiplicacion, OPERANDO(0) * OPERANDO(1), 0)
DECLARACION_FUNCION(OperadorDivision, OPERANDO(0) / OPERANDO(1), 0)
DECLARACION_FUNCION(OperadorNegativo, - OPERANDO(0), 0)
DECLARACION_FUNCION(FuncionRaizCuadrada, sqrt(VALOR_A_REAL(OPERANDO(0))), 1)
DECLARACION_FUNCION(FuncionPotencia, pow(VALOR_A_REAL(OPERANDO(0)), VALOR_A_REAL(OPERANDO(1))), 2)

DECLARACION_FUNCION(OperadorMenor, OPERANDO(0) < OPERANDO(1), 0);
DECLARACION_FUNCION(OperadorMenorIgual, OPERANDO(0) <= OPERANDO(1), 0);
DECLARACION_FUNCION(OperadorMayor, OPERANDO(0) > OPERANDO(1), 0);
DECLARACION_FUNCION(OperadorMayorIgual, OPERANDO(0) >= OPERANDO(1), 0);
DECLARACION_FUNCION(OperadorIgual, OPERANDO(0) == OPERANDO(1), 0);
DECLARACION_FUNCION(OperadorDistinto, OPERANDO(0) != OPERANDO(1), 0);
DECLARACION_FUNCION(OperadorAnd, OPERANDO(0) && OPERANDO(1), 0);
DECLARACION_FUNCION(OperadorOr, OPERANDO(0) || OPERANDO(1), 0);

